/**
 *  @author Ion Morozan
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.dddforandroid.database.local;

import java.lang.reflect.Type;
import java.text.ParseException;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;

import org.apache.http.impl.client.DefaultHttpClient;

import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.AsyncTask;
import android.util.Log;
import android.widget.DatePicker;
import android.widget.EditText;
import android.widget.Toast;

import com.dddforandroid.database.server.NotePad.Notes;
import com.dddforandroid.database.server.SyncServerDatabase;
import com.dddforandroid.design.ModifyTaskActivity;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;

public class UpdateNote extends AsyncTask<Void, Void, String> {

	/* The EditTexts for name, note and date */
	private final EditText nameET, noteET;

	private final DatePicker datePk;

	private final String noteID;
	/* The Context of the application */
	private Context mainActivity;
	/* The ServerDatabase object, used for synchronizing the server database */
	private SyncServerDatabase nosql;

	public DefaultHttpClient authClient = new DefaultHttpClient();

	/**
	 * Constructor used for the UpdateNote class
	 * 
	 * @param nameET
	 *            Name EditText
	 * @param noteET
	 *            Note EditText
	 * @param dateET
	 *            Date EditText
	 * @param mainActivity
	 *            The Context of the application
	 * @param nosql
	 *            The ServerDatabase object
	 */
	public UpdateNote(EditText nameET, EditText noteET, DatePicker datePk,
			String id, Context mainActivity, SyncServerDatabase nosql,
			DefaultHttpClient http_client) {
		this.datePk = datePk;
		this.nameET = nameET;
		this.noteET = noteET;
		this.noteID = id;
		this.mainActivity = mainActivity;
		this.nosql = nosql;
		this.authClient = http_client;
	}

	/**
	 * What the new thread is supposed to do in background - modify a Note which
	 * is in the database
	 */
	@Override
	protected String doInBackground(Void... params) {

		ContentValues newNote = new ContentValues();
		ContentResolver provider = mainActivity.getContentResolver();

		String putResponse = "Error";
		String name = nameET.getText().toString();
		String note = noteET.getText().toString();

		int year, month, day;
		day = datePk.getDayOfMonth();
		month = datePk.getMonth();
		year = datePk.getYear();

		
		Calendar cal = Calendar.getInstance(Locale.ENGLISH);
		cal.set(year, month, day);
		
		newNote.put(Notes.TITLE, name);
		newNote.put(Notes.NOTE, note);
		newNote.put(Notes.CREATED_DATE, cal.getTimeInMillis());

		Uri updateUri = Uri
				.parse(Notes.CONTENT_URI.toString());

		if (provider.update(updateUri, newNote, Notes._ID + " = '" + noteID + "'"
				, null) != 0) {
			/* Call the method to update the server database */
			try {
				putResponse = modifyServerDB(getModifiedNote(name, note));
			} catch (ParseException e) {
				Log.i("UpdateNote", "Provider does not containt the values");
				e.printStackTrace();
			}
		}

		return putResponse;
	}

	/**
	 * Invoked after the background computation finishes. The result of the
	 * background computation is passed to this step as a parameter.
	 */ 
	protected void onPostExecute(String result) {
		Toast.makeText(
				mainActivity,
				"Updated the name to: " + nameET.getText().toString()
						+ " and the description to: "
						+ noteET.getText().toString(), Toast.LENGTH_SHORT)
				.show();
		ModifyTaskActivity.progress.dismiss();
	}

	/**
	 * Method used to synchronize the databases when a Note was modified in the
	 * local database.
	 * 
	 * @param updatedNote
	 *            The note which was modified in the local database
	 * @return The response got from the server after calling HttpPut method
	 */
	private String modifyServerDB(Notes updatedNote) {
		GsonBuilder builder = new GsonBuilder();
		// Register an adapter to manage the date types as long values
		builder.registerTypeAdapter(Date.class, new JsonSerializer<Date>() {
			public JsonElement serialize(Date date, Type arg1,
					JsonSerializationContext arg2) {

				return new JsonPrimitive(date.getTime());
			}
		});
		Gson gson = builder.create();

		String JSONequiv = gson.toJson(updatedNote);

		/* Use the PUT Method to update the server database */
		String putResponse = nosql.putData(updatedNote.getId(), JSONequiv,
				authClient);

		Log.i("UpdateNote", "Server DB was updated - modified a note");

		return putResponse;
	}

	/**
	 * Method used to get all the fields of an Note object, when we only know
	 * the name and the description. This method is needed for synchronizing the
	 * databases when modifying or deleting a Note.
	 * 
	 * @param name
	 *            The name of the modified Note
	 * @param note
	 *            The description of the modified Note
	 * @return The whole Note
	 * @throws ParseException
	 */
	private Notes getModifiedNote(String name, String note)
			throws ParseException {
		ContentResolver provider = mainActivity.getContentResolver();
		/*
		 * Find the information about the updated note - the ID is needed for
		 * the PUT and DELETE methods
		 */
		Notes updatedNote = new Notes();

		String[] projection = new String[] { Notes._ID, Notes.TITLE, Notes.NOTE,
				Notes.CREATED_DATE};
		Uri queryUri = Notes.CONTENT_URI;
		/* Create a query */
		Cursor mCur = provider.query(queryUri, projection, Notes.TITLE + " = '"
				+ name + "'" 
		, null, null);

		if (mCur.moveToFirst()) {
			updatedNote = getCurrentNote(mCur);
		}

		mCur.close();
		return updatedNote;
	}

	/**
	 * Method used to initialize a new Note object with the current Strings from
	 * the database
	 * 
	 * @param mCur
	 *            The cursor used to move through the query results
	 * @return The Note object newly initialized
	 * @throws ParseException
	 */
	private Notes getCurrentNote(Cursor mCur) throws ParseException {
		Notes note = new Notes();

		note.setId(mCur.getString(mCur.getColumnIndex(Notes._ID)));
		note.setTitle(mCur.getString(mCur.getColumnIndex(Notes.TITLE)));
		note.setNote(mCur.getString(mCur.getColumnIndex(Notes.NOTE)));

		Long date_str = mCur.getLong(mCur.getColumnIndex(Notes.CREATED_DATE));

		note.setCreatedDate(date_str);

		return note;
	}

}
